PHP

Exposure of sensitive information

🐞 non-compliance
// Noncompliant code - exposing sensitive information in error log
function processUserInput($input) {
  // Process user input
  // ...
  
  // Log error with sensitive information
  error_log("Error processing user input: $input");
}
✅ compliance
// Compliant code - avoiding exposure of sensitive information in error log
function processUserInput($input) {
  // Process user input
  // ...
  
  // Log error without sensitive information
  error_log("Error processing user input"); // Log generic error message
}

Insertion of Sensitive Information Into Sent Data

🐞 non-compliance
// This code sends a user's password to a remote API as part of a JSON payload
$payload = json_encode(array('username' => 'alice', 'password' => 's3cret'));
$response = file_get_contents('https://example.com/api', null, stream_context_create(array(
    'http' => array(
        'method' => 'POST',
        'header' => "Content-Type: application/json\r\n",
        'content' => $payload,
    ),
)));
?>
✅ compliance
<?php
// This code sends a user's password to a remote API as a URL parameter using HTTPS
$username = 'alice';
$password = 's3cret';
$api_url = 'https://example.com/api?username=' . urlencode($username) . '&password=' . urlencode($password);
$response = file_get_contents($api_url, null, stream_context_create(array(
    'http' => array(
        'method' => 'GET',
    ),
)));
?>

Cross-Site Request Forgery (CSRF)

🐞 non-compliance
<form action="transfer.php" method="post">
    <input type="hidden" name="amount" value="1000">
    <input type="submit" value="Transfer Funds">
</form>
✅ compliance
<?php
session_start();
$_SESSION['token'] = bin2hex(random_bytes(32));
?>

<form action="transfer.php" method="post">
    <input type="hidden" name="amount" value="1000">
    <input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
    <input type="submit" value="Transfer Funds">
</form>

Use of Hard-coded Password

🐞 non-compliance
// This code includes a hard-coded password directly in the script
$password = "MyHardCodedPassword123";
$connection = mysqli_connect("localhost", "myuser", $password, "mydatabase");
✅ compliance
// This code stores the password in a separate configuration file with restricted access
$config = parse_ini_file("/etc/myapp/config.ini");
$connection = mysqli_connect("localhost", "myuser", $config['db_password'], "mydatabase");

Broken or Risky Crypto Algorithm

🐞 non-compliance
function encryptData($data, $key) {
    $iv = mcrypt_create_iv(16, MCRYPT_DEV_RANDOM);
    $encryptedData = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
    return $encryptedData;
}
✅ compliance
function encryptData($data, $key) {
    $iv = openssl_random_pseudo_bytes(16);
    $encryptedData = openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    return base64_encode($iv . $encryptedData);
}

Insufficient Entropy

🐞 non-compliance
$token = substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, 8);
✅ compliance
$token = bin2hex(random_bytes(16));

XSS

🐞 non-compliance
<?php
$username = $_GET['username'];
echo "Welcome " . $username . "!";
?>
✅ compliance
<?php
$username = htmlspecialchars($_GET['username'], ENT_QUOTES, 'UTF-8');
echo "Welcome " . $username . "!";
?>

SQL Injection

🐞 non-compliance
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$result = mysqli_query($conn, $sql);
✅ compliance
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = mysqli_real_escape_string($conn, $_POST['password']);

$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$result = mysqli_query($conn, $sql);

External Control of File Name or Path

🐞 non-compliance
$username = $_POST['username'];
$password = $_POST['password'];

$stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();
✅ compliance
$filename = basename($_GET['filename']);
$file = '/path/to/directory/' . $filename;
if (file_exists($file) && is_file($file)) {
  // do something with the file
} else {
  // handle error
}

Generation of Error Message Containing Sensitive Information

🐞 non-compliance
<?php
$username = $_POST['username'];
$password = $_POST['password'];
if ($username != 'admin' || $password != 'secretpass') {
  die('Invalid username or password!');
}
?>
✅ compliance
<?php
$username = $_POST['username'];
$password = $_POST['password'];
if ($username != 'admin' || $password != 'secretpass') {
  die('Invalid username or password!');
} else {
  // Valid login
}
?>

unprotected storage of credentials

🐞 non-compliance
$username = $_POST['username'];
$password = $_POST['password'];
$file = fopen('credentials.txt', 'w');
fwrite($file, "Username: $username, Password: $password");
fclose($file);
✅ compliance
$username = $_POST['username'];
$password = $_POST['password'];
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
$dbConnection = mysqli_connect('localhost', 'user', 'password', 'mydatabase');
$query = "INSERT INTO users (username, password) VALUES ('$username', '$hashedPassword')";
mysqli_query($dbConnection, $query);

Trust Boundary Violation

🐞 non-compliance
$user_id = $_GET['id'];
$query = "SELECT * FROM users WHERE id = ".$user_id;
$results = mysqli_query($conn, $query);
✅ compliance
$user_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($user_id === false) {
    // handle invalid input
} else {
    $stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->bind_param("i", $user_id);
    $stmt->execute();
    $results = $stmt->get_result();
}

Insufficiently Protected Credentials

🐞 non-compliance
$password = $_POST['password'];
$hashed_password = sha1($password);
$query = "INSERT INTO users (username, password) VALUES ('{$_POST['username']}', '{$hashed_password}')";
mysqli_query($conn, $query);
✅ compliance
$password = $_POST['password'];
if (strlen($password) < 8) {
    // Handle error: password must be at least 8 characters long
}
$salt = bin2hex(random_bytes(16));
$hashed_password = password_hash($password . $salt, PASSWORD_ARGON2ID);
$stmt = $conn->prepare("INSERT INTO users (username, password, salt) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $_POST['username'], $hashed_password, $salt);
$stmt->execute();

Restriction of XML External Entity Reference

🐞 non-compliance
$xml = simplexml_load_string($xmlstring, 'SimpleXMLElement', LIBXML_NOENT);

// use $xml here
✅ compliance
$disableEntities = libxml_disable_entity_loader(true);
$xml = simplexml_load_string($xmlstring, 'SimpleXMLElement', LIBXML_NOENT);
libxml_disable_entity_loader($disableEntities);

// use $xml here

Vulnerable and Outdated Components

🐞 non-compliance
<?php
// Example of vulnerable and outdated components
// using an old version of PHPMailer library

require_once 'PHPMailer/class.phpmailer.php';

$mail = new PHPMailer();

$mail->IsSMTP();
$mail->SMTPDebug = 1;
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'ssl';

$mail->Host = 'smtp.gmail.com';
$mail->Port = 465;

$mail->Username = '[email protected]';
$mail->Password = 'password';

$mail->SetFrom('[email protected]', 'From Name');
$mail->AddReplyTo('[email protected]', 'Reply-to Name');

$mail->Subject = 'Test email';
$mail->Body = 'This is a test email';

$mail->AddAddress('[email protected]', 'Recipient Name');

if (!$mail->Send()) {
    echo 'Message could not be sent.';
    echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
    echo 'Message has been sent.';
}
?>
✅ compliance
<?php
// Example of secure and up-to-date code
// using the latest version of PHPMailer library

require_once 'PHPMailer/src/PHPMailer.php';
require_once 'PHPMailer/src/SMTP.php';

$mail = new PHPMailer\PHPMailer\PHPMailer(true);

$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = '[email protected]';
$mail->Password = 'password';
$mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;

$mail->setFrom('[email protected]', 'From Name');
$mail->addAddress('[email protected]', 'Recipient Name');

$mail->isHTML(true);
$mail->Subject = 'Test email';
$mail->Body = 'This is a test email';

if (!$mail->send()) {
    echo 'Message could not be sent.';
    echo 'Mailer Error: ' . $mail->ErrorInfo;

Improper Validation of Certificate with Host Mismatch

🐞 non-compliance
$host = $_SERVER['HTTP_HOST'];
$opts = array('ssl' => array('verify_peer' => true, 'CN_match' => $host));
$context = stream_context_create($opts);
$data = file_get_contents('https://example.com', false, $context);
✅ compliance
$host = 'example.com';
$opts = array('ssl' => array('verify_peer' => true, 'CN_match' => $host));
$context = stream_context_create($opts);
$data = file_get_contents('https://'.$host, false, $context);

Improper Authentication

🐞 non-compliance
// Example 1: Weak Password
$password = $_POST['password'];
if ($password === 'password123') {
    // Allow access
} else {
    // Deny access
}

// Example 2: Hardcoded Credentials
$username = 'admin';
$password = 'password';
if ($_POST['username'] === $username && $_POST['password'] === $password) {
    // Allow access
} else {
    // Deny access
}
✅ compliance
// Example 1: Strong Password
$password = $_POST['password'];
if (password_verify($password, $hashedPassword)) {
    // Allow access
} else {
    // Deny access
}

// Example 2: Stored Credentials
$username = $_POST['username'];
$password = $_POST['password'];

// Validate the user's credentials against a secure database
if (validateCredentials($username, $password)) {
    // Allow access
} else {
    // Deny access
}

Session Fixation

🐞 non-compliance
<?php
session_start();
if (isset($_POST['username']) && isset($_POST['password'])) {
  $username = $_POST['username'];
  $password = $_POST['password'];
  if (authenticate($username, $password)) {
    $_SESSION['authenticated'] = true;
    $_SESSION['username'] = $username;
  }
}
?>
✅ compliance
<?php
session_start();
if (isset($_POST['username']) && isset($_POST['password'])) {
  $username = $_POST['username'];
  $password = $_POST['password'];
  if (authenticate($username, $password)) {
    // Regenerate session ID after successful login
    session_regenerate_id();
    $_SESSION['authenticated'] = true;
    $_SESSION['username'] = $username;
  }
}
?>

Inclusion of Functionality from Untrusted Control

🐞 non-compliance
<?php
$remoteUrl = $_GET['url'];
include($remoteUrl);
?>
✅ compliance
<?php
$remoteUrl = $_GET['url'];
if (filter_var($remoteUrl, FILTER_VALIDATE_URL)) {
  include($remoteUrl);
} else {
  // handle error
}
?>

Download of Code Without Integrity Check

🐞 non-compliance
$url = 'https://example.com/package.tar.gz';
$pkg = file_get_contents($url);
file_put_contents('/tmp/package.tar.gz', $pkg);
system('tar -xvf /tmp/package.tar.gz');
✅ compliance
$url = 'https://example.com/package.tar.gz';
$hash = file_get_contents($url . '.sha256');
$pkg = file_get_contents($url);

if (hash('sha256', $pkg) === trim($hash)) {
    file_put_contents('/tmp/package.tar.gz', $pkg);
    system('tar -xvf /tmp/package.tar.gz');
} else {
    throw new Exception('Package hash does not match expected value');
}

Deserialization of Untrusted Data

🐞 non-compliance
// Noncompliant code for Deserialization of Untrusted Data

// unserialize() function is used to deserialize the input data from a string
$userData = unserialize($_COOKIE['user']);

// Use the data from $userData
$name = $userData['name'];
$id = $userData['id'];
✅ compliance
// Compliant code for Deserialization of Untrusted Data

// Deserialize the input data after validating and sanitizing it
$userData = json_decode(filter_input(INPUT_COOKIE, 'user', FILTER_SANITIZE_STRING));

// Use the data from $userData
if (isset($userData->name)) {
    $name = $userData->name;
}
if (isset($userData->id)) {
    $id = $userData->id;
}

Insufficient Logging

🐞 non-compliance
function transferMoney($amount, $recipient) {
  // some code to transfer money
  // ...
  
  // log the transaction
  file_put_contents('transaction.log', "Transfered $amount to $recipient", FILE_APPEND);
}
✅ compliance
function transferMoney($amount, $recipient) {
  // some code to transfer money
  // ...
  
  // log the transaction with useful information
  $log = fopen('transaction.log', 'a');
  if ($log) {
    $datetime = date('Y-m-d H:i:s');
    $severity = 'INFO';
    $message = "Transfered $amount to $recipient";
    $entry = "$datetime [$severity]: $message\n";
    fwrite($log, $entry);
    fclose($log);
  } else {
    error_log('Unable to open transaction log file');
  }
}

Improper Output Neutralization for Logs

🐞 non-compliance
$username = $_POST['username'];
$password = $_POST['password'];

// log the username and password to a file
file_put_contents('logs.txt', 'Username: '.$username.' Password: '.$password);
✅ compliance
$username = $_POST['username'];
$password = $_POST['password'];

// sanitize the input using filter_var
$sanitized_username = filter_var($username, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
$sanitized_password = filter_var($password, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);

// log the sanitized username and password to a file
file_put_contents('logs.txt', 'Username: '.$sanitized_username.' Password: '.$sanitized_password);

Omission of Security-relevant Information

🐞 non-compliance
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT * FROM users WHERE username = '" . $username . "' AND password = '" . $password . "'";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
    // user is authenticated
    // do some sensitive operation
} else {
    // user is not authenticated
    echo "Invalid credentials";
}
✅ compliance
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT * FROM users WHERE username = ? AND password = ?";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, "ss", $username, $password);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

if (mysqli_num_rows($result) > 0) {
    // user is authenticated
    // do some sensitive operation
} else {
    // user is not authenticated
    echo "Invalid credentials";
}

Sensitive Information into Log File

🐞 non-compliance
// sensitive data is logged without proper redaction
$username = $_POST['username'];
$password = $_POST['password'];

error_log("Login attempt with username: ".$username." and password: ".$password);
✅ compliance
// sensitive data is redacted before being logged
$username = $_POST['username'];
$password = $_POST['password'];

error_log("Login attempt with username: ".redact($username)." and password: ".redact($password));

function redact($string) {
  // replace sensitive data with asterisks
  return preg_replace('/./', '*', $string);
}

Server-Side Request Forgery (SSRF)

🐞 non-compliance
$url = $_GET['url'];
$file = file_get_contents($url);
echo $file;
✅ compliance
$url = $_GET['url'];
if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) {
    echo "Invalid URL";
} else {
    $file = file_get_contents($url);
    echo $file;
}